package gameFile;

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
import java.lang.Math; 
//import java.util.Iterator;

public class GamePlay {

    public enum Action { GOSTRAIGHT, GOLEFT, GORIGHT }
	public enum Direction {	UP, LEFT, DOWN, RIGHT }	
	public enum Axis { UPDOWN, LEFTRIGHT }
	public enum VSMode {VSCOMPUTER,VSHUMAN }
	public enum Difficulty {EASY, MEDIUM, HARD }
	
	public Random rand = new Random();
	public ArrayList<WallSegment> wallsUD, wallsLR;
    public LightBike players[];
    public WallSegment playerWalls[];
    //public int playerCount;
    public VSMode mode;
    public int Width, Height;
    public boolean gameOver = false;
    public Difficulty difficult;
        
    public GamePlay(VSMode gameMode,int Width,int Height) {
    	wallsUD = new ArrayList<WallSegment>(63);
    	wallsLR = new ArrayList<WallSegment>(63);
    	this.Width = Width;
    	this.Height = Height;
    	rand.setSeed(System.currentTimeMillis());
    	
    	switch(gameMode)
    	{
    	case VSHUMAN:
    		players = new LightBike[2];
    		playerWalls = new WallSegment[2];
        	players[0] = new HumanPlayer(0,50,50,1,Direction.DOWN,Color.cyan);
        	players[1] = new HumanPlayer(0,50,200,1,Direction.LEFT,Color.magenta);
        	playerWalls[0] = new WallSegment(players[0]);
        	playerWalls[1] = new WallSegment(players[1]);
    		break;
    	default:
    		players = new LightBike[4];    		
        	players[0] = new HumanPlayer(0,50,50,1,Direction.DOWN,Color.cyan);        
        	players[1] = new AIBot(1, 55, 150, 1, Direction.RIGHT);    		
    		players[2] = new AIBot(2, 350, 145, 1, Direction.UP);    		
    		players[3] = new AIBot(3, 345, 350, 1, Direction.LEFT); 
    		
    		playerWalls = new WallSegment[4];    
    		difficult = Difficulty.MEDIUM;
        	for(int i=0;i<4;i++)
        		playerWalls[i] = new WallSegment(players[i]);
        	
    		break;
    	}
    	mode = gameMode;
    }
    
    public void setHumanAction(int ID, Action action)
    {
    	for(LightBike lb:players)
    	{
    		if(lb.getClass() == HumanPlayer.class) {
    			if(lb.getID() == ID) lb.setAction(action);
    		}
    	}
    }
    
    public void setAIAction(int ID)
    {
    	switch(difficult)
    	{    	
    	case MEDIUM:
    		int front = pulseRadar(players[ID].getXPosition(),
    				players[ID].getYPosition(),players[ID].direction);
    		players[ID].distance = front;
    		if(isBetween(front,rand.nextInt(15),rand.nextInt(20)+8)){
    			if(rand.nextBoolean())
    				players[ID].setAction(Action.GOLEFT);
    			else 
    				players[ID].setAction(Action.GORIGHT); 				
    		}
    		if(front > Math.min(Width,Height)/4){
    			switch(rand.nextInt(180))    		{
        		case 0:
        			players[ID].setAction(Action.GOLEFT);	break;
        		case 1:
        			players[ID].setAction(Action.GORIGHT);	break;
        		}
    		}
    		break;
    	case EASY:
    		switch(rand.nextInt(180))    		{
    		case 0:
    			players[ID].setAction(Action.GOLEFT);	break;
    		case 1:
    			players[ID].setAction(Action.GORIGHT);	break;
    		}
    	}
    	
    }

	public boolean detectCollision(LightBike player) {
		// player's coordinates
		int x = player.getXPosition();
		int y = player.getYPosition();
		int speed = player.getSpeed();
		
		// collisions with border
		if(x > Width  || x < 0)	
			return true;
		if(y > Height || y < 0)
			return true;			
		
		// collisions normal to the wall
		switch(player.direction) 
		{
		case UP:
		case DOWN:
			for (WallSegment w: wallsLR) {	
				if (isBetween(x, w.getXstart(), w.getXend())){
					//System.out.println("player within horizontal");
					if (y > w.getYstart() - speed && y < w.getYstart() + speed){
						if(!w.fixed && w.getID() == player.getID())
							w.fixed = true;
						else {
							System.out.println("coll on leftright");						
							return true;
							}
					}
				}				
			}
			break;
		case LEFT:
		case RIGHT:
			for (WallSegment w: wallsUD) {	
				if (isBetween(y, w.getYstart(), w.getYend())){
					//System.out.println("player within horizontal");
					if (x > w.getXstart() - speed && x < w.getXstart() + speed){
						if(!w.fixed && w.getID() == player.getID())
							w.fixed = true;
						else {
							System.out.println("coll on leftright");
							return true;
						}
					}
				}				
			}
		}
		
		// collisions with end of wall
		switch(player.direction)
		{
		case UP:
		case DOWN:
			for (WallSegment w: wallsUD) {
				if (w.getXstart() == x){
					if(isBetween(y, w.getYstart(), w.getYend())){
						if(!w.fixed && w.getID() == player.getID())
							w.fixed = true;
						else
							return true;
					}
				}
			}
			break;
			
		case LEFT:
		case RIGHT:
			for (WallSegment w: wallsLR) {
				if (w.getYstart() == y){
					if(isBetween(x, w.getXstart(), w.getXend())) {
						if(!w.fixed && w.getID() == player.getID())
							w.fixed = true;
						else
							return true;
					}
				}
			}
			break;
		}
		return false;
	}
	
	public void playTurn()
	{
		WallSegment temp = null;
		int playersRemaining = 0;
		for(LightBike pl: players){
			if(pl.getClass() == AIBot.class){
				setAIAction(pl.getID());
			}
		}
			
		
		for(LightBike pl: players)
		{
			if(pl.isAlive()){
				
				temp = pl.playTurn();
				playersRemaining++;
				if(temp != null)
				{
					switch(temp.axis)
					{
					case UPDOWN:
						wallsUD.add(temp);
						break;
					case LEFTRIGHT:
						wallsLR.add(temp);
						break;
					}
				}
				
				if(detectCollision(pl)) 
				{
					pl.playerDeath();
					temp = pl.getTrailingWall();
					switch(temp.axis)
					{
					case UPDOWN:
						wallsUD.add(temp);
						break;
					case LEFTRIGHT:
						wallsLR.add(temp);
						break;
					}
				}						
			}
			
		}
		if((!players[0].isAlive() && mode == VSMode.VSCOMPUTER) || playersRemaining == 1)
			gameOver = true;
	}
	
	public void drawGame(Graphics g){
		for (WallSegment w:wallsUD){
			w.drawWall(g);
		}
		for (WallSegment w:wallsLR){
			w.drawWall(g);
		}
		for (WallSegment w:playerWalls){
			w.drawWall(g);
		}
		for(LightBike lb: players)
		{
			lb.drawBike(g);
			lb.drawWall(g);
		}
		
	}
	
	public int pulseRadar(int x, int y, Direction dir)
	{
		int dist = 0x7FFFFFFF;
		
		switch(dir)
		{
		case UP:
			dist = y;
			// y less than wall Y: set dist
			for(WallSegment w: wallsUD)	{
				if(w.getXstart() == x){
					if(y - w.getYstart() < dist && w.getYstart() < y)
						dist = y - w.getYstart();
					if(y - w.getYend() < dist && w.getYend() < y)
						dist = y - w.getYend();
				}		
			}
			for(WallSegment w:wallsLR){
				if(w.getYstart() < y){
					if(isBetween(x,w.getXstart(),w.getXend())) {
						if(y - w.getYstart() < dist) {
							dist = y - w.getYstart();
						}
					}
				}
			}
			break;
		
		case DOWN:
			dist = Height - y;
			for(WallSegment w: wallsUD)	{
				if(w.getXstart() == x){
					if(w.getYstart() - y < dist && w.getYstart() > y)
						dist = w.getYstart() - y;
					if(w.getYend() - y < dist && w.getYend() > y)
						dist = w.getYend() - y;
				}		
			}
			for(WallSegment w:wallsLR){
				if(w.getYstart() > y){
					if(isBetween(x,w.getXstart(),w.getXend())) {
						if(w.getYstart() - y < dist) {
							dist = w.getYstart() - y;
						}
					}
				}
			}
			break;
		
		case LEFT:
			dist = x;
			for(WallSegment w: wallsLR)	{
				if(w.getYstart() == y){
					if(x - w.getXstart() < dist && w.getXstart() < x)
						dist = x - w.getXstart();
					if(x - w.getXend() < dist && w.getXend() < x)
						dist = x - w.getXend();
				}		
			}
			for(WallSegment w:wallsUD){
				if(w.getXstart() < x){
					if(isBetween(y,w.getYstart(),w.getYend())) {
						if(x - w.getXstart() < dist) {
							dist = x - w.getXstart();
						}
					}
				}
			}
			break;
		
		case RIGHT:
			dist = Width - x;
			for(WallSegment w: wallsLR)	{
				if(w.getYstart() == y){
					if(w.getXstart() - x < dist && w.getXstart() > x)
						dist = w.getXstart() - x;
					if(w.getXend() - x < dist && w.getXend() > x)
						dist = w.getXend() - x;
				}		
			}
			for(WallSegment w:wallsUD){
				if(w.getXstart() > x){
					if(isBetween(y,w.getYstart(),w.getYend())) {
						if(w.getXstart() - x < dist) {
							dist = w.getXstart() - x;
						}
					}
				}
			}
			break;
		}
		
		return dist;
	}
	
	public boolean isBetween(int testVal, int outer1, int outer2)
	{
		int min,max;
		if(outer1 < outer2) {
			min = outer1; max = outer2;
		}
		else {
			min=outer2;max=outer1;
		}
		
		if(testVal >= min && testVal <= max)
			return true;
		else
			return false;
	}
	

    
}